/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.mts.core.service.impl;

import com.google.common.collect.Lists;
import com.intelligent.mts.common.utils.ApplicationException;
import com.intelligent.mts.common.utils.ExceptionMessages;
import com.intelligent.mts.common.utils.StringUtils;
import com.intelligent.mts.core.dao.*;
import com.intelligent.mts.core.dto.*;
import com.intelligent.mts.core.entity.*;
import com.intelligent.mts.core.service.DataSearchService;
import com.intelligent.mts.core.utils.AppConst;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by cherry on 2016/7/26.
 */
@Service
public class DataSearchServiceImpl implements DataSearchService {

    private final Logger logger = LoggerFactory.getLogger(DataSearchServiceImpl.class);

    @Autowired
    private ProductionDao productionDao;

    @Autowired
    private SerialNumberDao serialNumberDao;

    @Autowired
    private AttributeDao attributeDao;

    @Autowired
    private HistoryDao historyDao;

    @Autowired
    private TrackDao trackDao;

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private FinishGoodDao finishGoodDao;

    @Override
    public void createProduction(ProductionDto productionDto) {
        logger.debug("createProduction parameter is: " + productionDto.toString());
        if (productionDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Production production = new Production();
        BeanUtils.copyProperties(productionDto, production);
        logger.debug("create production: " + production.toString());
        productionDao.save(production);
        logger.debug("save production success!");
    }

    @Override
    public String updateProduction(String HsproductionId, String HouproductionId, String parentId) {
        logger.debug("updateProduction parameter is: " + HsproductionId + ", "+ HouproductionId + ", " + parentId);
        if (HsproductionId == null ||HouproductionId ==null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Production Hsproduction = productionDao.findByProductionId(HsproductionId);
        Production Houproduction = productionDao.findByProductionId(HouproductionId);
        Production Parproduction = productionDao.findByProductionId(parentId);
        List<ProductionDto> HsproductionDtos = findByProductionIdOrParentId(HsproductionId);
        List<ProductionDto> HouproductionDtos = findByProductionIdOrParentId(HouproductionId);
        ProductionDto HsproductionDto = findProductionByProductionId(HsproductionId);
        ProductionDto HouproductionDto = findProductionByProductionId(HouproductionId);
        String fgpn = Hsproduction.getFgPn();
        int HsCount = 0;
        int HouCount = 0;
        HsCount = HsproductionDtos.size();
        HouCount = HouproductionDtos.size();

        if (HsCount == 1 && HouCount ==1){
            updateParProductionId(HsproductionId, HouproductionId, parentId);
            ProductionDto productionDto = new ProductionDto();
            productionDto.setProductionId(parentId);
            productionDto.setFgPn(fgpn);
            createProduction(productionDto);
        }else if (HsCount == 1 && (HouCount ==2 || HouCount ==3)){
            if (HouproductionDto.getChindrenId().isEmpty()){
                HouproductionId = HouproductionDto.getProductionId();
                parentId = HouproductionDto.getParentId();
            }else {
                if (org.apache.commons.lang3.StringUtils.isBlank(HouproductionDto.getChindrenId().get(0).getFgPn())){
                    HouproductionId = HouproductionDto.getChindrenId().get(0).getProductionId();
                }else {
                    HouproductionId = HouproductionDto.getChindrenId().get(1).getProductionId();
                }
                parentId = HouproductionDto.getProductionId();
            }
            updateParProductionId(HsproductionId, HouproductionId, parentId);
        }else if ((HsCount ==2 || HsCount ==3) && HouCount ==1) {
            if (HsproductionDto.getChindrenId().isEmpty()){
                HsproductionId = HsproductionDto.getProductionId();
                parentId = HsproductionDto.getParentId();
            }else {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(HsproductionDto.getChindrenId().get(0).getFgPn())){
                    HsproductionId = HsproductionDto.getChindrenId().get(0).getProductionId();
                }else {
                    HsproductionId = HsproductionDto.getChindrenId().get(1).getProductionId();
                }
                parentId = HsproductionDto.getProductionId();
            }
            updateParProductionId(HsproductionId, HouproductionId, parentId);
        }else if ((HsCount ==2 || HsCount ==3) && (HouCount ==2 || HouCount ==3)){
            if (HsproductionDto.getChindrenId().isEmpty()){
                HsproductionId = HsproductionDto.getProductionId();
                parentId = HsproductionDto.getParentId();
            }else {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(HsproductionDto.getChindrenId().get(0).getFgPn())){
                    HsproductionId = HsproductionDto.getChindrenId().get(0).getProductionId();
                }else {
                    HsproductionId = HsproductionDto.getChindrenId().get(1).getProductionId();
                }
                parentId = HsproductionDto.getProductionId();
            }
            if (HouproductionDto.getChindrenId().isEmpty()){
                HouproductionId = HouproductionDto.getProductionId();
            }else {
                if (org.apache.commons.lang3.StringUtils.isBlank(HouproductionDto.getChindrenId().get(0).getFgPn())){
                    HouproductionId = HouproductionDto.getChindrenId().get(0).getProductionId();
                }else {
                    HouproductionId = HouproductionDto.getChindrenId().get(1).getProductionId();
                }
            }
            updateParProductionId(HsproductionId, HouproductionId, parentId);
        }else {
            logger.error("two more production exits ParentproductionId");
            return null;
        }
        logger.debug("update production: " + Hsproduction.toString() + Houproduction.toString());
        productionDao.update(Hsproduction);
        productionDao.update(Houproduction);
        logger.debug("update production success!");
        return parentId;
    }

    public void updateParProductionId(String HsproductionId, String HouproductionId, String parentId) {
        logger.debug("updateProductionId parameter is: " + HsproductionId + ", "+ HouproductionId + ", " + parentId);
        if (HsproductionId == null ||HouproductionId ==null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        Production Hsproduction = productionDao.findByProductionId(HsproductionId);
        Production Houproduction = productionDao.findByProductionId(HouproductionId);
        Production Parproduction = productionDao.findByProductionId(parentId);
        String fgpn = Hsproduction.getFgPn();

        if (Parproduction !=null){
            for (Production production3: Parproduction.getChindrenId()){
                production3.setParentId(null);
                productionDao.update(production3);
            }
            Parproduction.setFgPn(fgpn);
            productionDao.update(Parproduction);
        }
        if (Hsproduction != null && Houproduction != null) {
            Hsproduction.setParentId(parentId);
            Houproduction.setParentId(parentId);
        }

        logger.debug("update productionId: " + Hsproduction.toString() + Houproduction.toString());
        productionDao.update(Hsproduction);
        productionDao.update(Houproduction);
        logger.debug("update productionId success!");
    }

    @Override
    public String findHsProductionId(String productionId) {
        logger.debug("getHsProductionId parameter is: " + productionId);
        if (productionId == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String HsproductionId = "";
        ProductionDto productionDto = findProductionByProductionId(productionId);
        if (productionDto.getChindrenId().isEmpty()){
            HsproductionId = productionId;
        }else {
            if (com.intelligent.mts.common.utils.StringUtils.isNotBlank(productionDto.getChindrenId().get(0).getFgPn())){
                HsproductionId = productionDto.getChindrenId().get(0).getProductionId();
            }else {
                HsproductionId = productionDto.getChindrenId().get(1).getProductionId();
            }
        }
        return HsproductionId;
    }

    @Override
    public ProductionDto findProductionByProductionId(String productionId) {
        logger.debug("findProductionByProductionId parameter is: " + productionId);
        if (productionId == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Production production = new Production();
        production = productionDao.findByProductionId(productionId);
        //logger.debug("search production result: " + production.toString());
        ProductionDto productionDto = null;
        if (production != null) {
            productionDto = new ProductionDto();
            BeanUtils.copyProperties(production, productionDto);
        }
        return productionDto;
    }

    @Override
    public List<ProductionDto> findByProductionIdOrParentId(String id) {
        logger.debug("findByProductionIdOrParentId parameter is: " + id);
        if (StringUtils.isBlank(id)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<Production> productionList = productionDao.findByProductionIdOrParentId(id);
        logger.debug("search production list size: " + productionList.size());
        List<ProductionDto> productionDtoList = Lists.newArrayList();
        for (Production production : productionList) {
            ProductionDto productionDto = new ProductionDto();
            BeanUtils.copyProperties(production, productionDto);
            productionDtoList.add(productionDto);
        }
        return productionDtoList;
    }

    @Override
    public void createSerialNumber(SerialNumberDto serialNumberDto) {
        logger.debug("createSerialNumber parameter is: " + serialNumberDto);
        if (serialNumberDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        SerialNumber serialNumber1 = serialNumberDao.findByPSS(serialNumberDto.getProductionId(), serialNumberDto.getStationId(), AppConst.SN_HS);
        if (serialNumber1 != null){
            List<SerialNumber> serialNumberList = serialNumberDao.findBySerialValue(serialNumber1.getSerialValue());
            if (serialNumberList != null && !serialNumberList.isEmpty()){
                serialNumberDao.delete(serialNumberList.get(0).getId());
            }
        }
        SerialNumber serialNumber = new SerialNumber();
        BeanUtils.copyProperties(serialNumberDto, serialNumber);
        logger.debug("create serialNumber: " + serialNumber);
        serialNumberDao.save(serialNumber);
        logger.debug("save serialNumber successs !");
    }

    @Override
    public void updateSerialNumber(SerialNumberDto serialNumberDto) {
        logger.debug("updateSerialNumber parameter is: " + serialNumberDto);
        if (serialNumberDto == null || StringUtils.isBlank(serialNumberDto.getProductionId())
                || StringUtils.isBlank(serialNumberDto.getStationId())
                || StringUtils.isBlank(serialNumberDto.getSerialName())) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        SerialNumber serialNumber = serialNumberDao.findByPSS(serialNumberDto.getProductionId(), serialNumberDto.getStationId(), serialNumberDto.getSerialName());
        if (serialNumber != null) {
            Long id = serialNumber.getId();
            BeanUtils.copyProperties(serialNumberDto, serialNumber);
            logger.debug("update serialNumber: " + serialNumber);
            serialNumber.setId(id);
            serialNumberDao.update(serialNumber);
            logger.debug("update serialNumber success!");
        }
        else {
            logger.error("can not find this serialNumber whose production id is : " + serialNumberDto.getProductionId());
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
    }


    @Override
    public List<SerialNumberDto> findSnBySerialValue(String serialValue) {
        logger.debug("findSnBySerialValue parameter is: " + serialValue);
        if (serialValue == null || "".equals(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<SerialNumber> serialNumberList = serialNumberDao.findBySerialValue(serialValue);
        List<SerialNumberDto> serialNumberDtoList = Lists.newArrayList();
        if (serialNumberList != null) {
            for (SerialNumber serialNumber: serialNumberList) {
                SerialNumberDto serialNumberDto = new SerialNumberDto();
                BeanUtils.copyProperties(serialNumber, serialNumberDto);
                serialNumberDtoList.add(serialNumberDto);
            }
        }
        return serialNumberDtoList;
    }


    @Override
    public SerialNumberDto findCondition(String productionId, String stationId, String snName) {
        logger.debug("findCondition parameter is: " + productionId);
        if (StringUtils.isBlank(productionId) || StringUtils.isBlank(stationId) || StringUtils.isBlank(snName)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        SerialNumber serialNumber = serialNumberDao.findByPSS(productionId, stationId, snName);
        SerialNumberDto serialNumberDto = null;

        if (serialNumber != null) {
            serialNumberDto = new SerialNumberDto();
            BeanUtils.copyProperties(serialNumber, serialNumberDto);
        }
        return serialNumberDto;
    }


    @Override
    public List<SerialNumberDto> findSnByStationId(String stationId, String productionId) {
        logger.debug("findSnByStationId parameter is: " + stationId);
        if (stationId == null || "".equals(stationId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<SerialNumberDto> serialNumberDtoList = Lists.newArrayList();
        List<SerialNumber> serialNumberList = serialNumberDao.findByStationId(stationId, productionId);
        logger.debug("find serialNumber list size: " + serialNumberList.size());
        for (SerialNumber serialNumber : serialNumberList) {
            SerialNumberDto serialNumberDto = new SerialNumberDto();
            BeanUtils.copyProperties(serialNumber, serialNumberDto);
            serialNumberDtoList.add(serialNumberDto);
        }
        return serialNumberDtoList;
    }

    @Override
    public String findProductionIdBySerialValue(String serialValue) {
        logger.debug("findProductionIdBySerialValue parameter is: " + serialValue);
        if (serialValue == null || "".equals(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        if (StringUtils.isBlank(productionId)) {
            return null;
        }
        productionId = this.getProductionIdOrParentIdBySnId(productionId);
        logger.debug("find productionId result: " + productionId);
        return productionId;
    }

    @Override
    public List<SerialNumberDto> findSnListByProductionId(String productionId) {
        logger.debug("findSnListByProductionId parameter is: " + productionId);
        if (StringUtils.isBlank(productionId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<Production> productionList = findProductionById(productionId);
        List<SerialNumber> serialNumberList = Lists.newArrayList();
        for (Production production : productionList) {
            String id = production.getProductionId();
            List<SerialNumber> list = serialNumberDao.findByProductionId(id);
            serialNumberList.addAll(list);
        }
        logger.debug("total serialNumber list size: " + serialNumberList.size());
        List<SerialNumberDto> serialNumberDtoList = Lists.newArrayList();
        for (SerialNumber serialNumber : serialNumberList) {
            SerialNumberDto serialNumberDto = new SerialNumberDto();
            BeanUtils.copyProperties(serialNumber, serialNumberDto);
            serialNumberDtoList.add(serialNumberDto);
        }

        return serialNumberDtoList;
    }

    @Override
    public List<SerialNumberDto> findAllSnListBySerialValue(String serialValue) {
        logger.debug("findAllSnListBySerialValue parameter is: " + serialValue);
        List<SerialNumber> serialNumberList = Lists.newArrayList();
        List<SerialNumberDto> serialNumberDtoList = Lists.newArrayList();
        if (serialValue == null || "".equals(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        if (StringUtils.isNotBlank(productionId)) {
            List<Production> productionList = findProductionById(productionId);
            for (Production production : productionList) {
                String id = production.getProductionId();
                List<SerialNumber> list = serialNumberDao.findByProductionId(id);
                serialNumberList.addAll(list);
            }
            logger.debug("total serialNumber list size: " + serialNumberList.size());
            for (SerialNumber serialNumber : serialNumberList) {
                SerialNumberDto serialNumberDto = new SerialNumberDto();
                BeanUtils.copyProperties(serialNumber, serialNumberDto);
                serialNumberDtoList.add(serialNumberDto);
            }
        }
        return serialNumberDtoList;
    }

    @Override
    public void createTrack(TrackDto trackDto) {
        logger.debug("createTrack parameter is: " + trackDto);
        if (trackDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Track track = new Track();
        BeanUtils.copyProperties(trackDto, track);
        logger.debug("create track: " + track);
        trackDao.save(track);
        logger.debug("save track success!");
    }

    @Override
    public void update(TrackDto trackDto) {
        logger.debug("updateTrack parameter is: " + trackDto);
        if (trackDto == null || trackDto.getProductionId() == null || "".equals(trackDto.getProductionId())) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Track track = trackDao.findByProductionId(trackDto.getProductionId());
        if (track != null) {
            BeanUtils.copyProperties(trackDto, track);
            logger.debug("update track: " + track);
            trackDao.update(track);
            logger.debug("update track success!");
        }
        else {
            logger.error("can not find this track whose production id is : " + trackDto.getProductionId());
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
    }

    @Override
    public TrackDto findTrackByProductionId(String productionId) {
        logger.debug("findTrackByProductionId parameter is: " + productionId);
        if (productionId == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Track track = trackDao.findByProductionId(productionId);
        logger.debug("search track result: " + track);
        TrackDto trackDto = null;
        if (track != null) {
            trackDto = new TrackDto();
            BeanUtils.copyProperties(track, trackDto);
        }
        return trackDto;
    }

    @Override
    public TrackDto findTrackBySerialValue(String serialValue) {
        logger.debug("findTrackBySerialValue parameter is: " + serialValue);
        if (serialValue == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        logger.debug("search productionId result: " + productionId);
        productionId = this.getProductionIdOrParentIdBySnId(productionId);
        Track track = trackDao.findByProductionId(productionId);
        logger.debug("search track result: " + track);
        TrackDto trackDto = null;
        if (track != null) {
            trackDto = new TrackDto();
            BeanUtils.copyProperties(track, trackDto);
        }
        return trackDto;
    }

    @Override
    public void createAttribute(AttributeDto attributeDto) {
        logger.debug("createAttribute parameter is: " + attributeDto);
        if (attributeDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        Attribute attribute = new Attribute();
        BeanUtils.copyProperties(attributeDto, attribute);
        logger.debug("create attribute: " + attribute);
        attributeDao.save(attribute);
        logger.debug("save attribute success!");
    }

    @Override
    public List<AttributeDto> findAttributeListBySerialValue(String serialValue) {
        logger.debug("findAttributeListBySerialValue parameter is: " + serialValue);
        if (serialValue == null || ("").equals(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        logger.debug("search productionId result: " + productionId);
        List<Production> productionList = findProductionById(productionId);
        List<Attribute> attributeList = Lists.newArrayList();
        for (Production production : productionList) {
            String id = production.getProductionId();
            List<Attribute> list = attributeDao.findByProductionId(id);
            attributeList.addAll(list);
        }
        logger.debug("search total attribute list size: " + attributeList.size());
        List<AttributeDto> attributeDtoList = Lists.newArrayList();
        for (Attribute attribute : attributeList) {
            AttributeDto attributeDto = new AttributeDto();
            BeanUtils.copyProperties(attribute, attributeDto);
            attributeDtoList.add(attributeDto);
        }
        return attributeDtoList;
    }

    @Override
    public void createHistory(HistoryDto historyDto) {
        logger.debug("createHistory parameter is: " + historyDto);
        if (historyDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        History history = new History();
        BeanUtils.copyProperties(historyDto, history);
        logger.debug("create history: " + history);
        historyDao.save(history);
        logger.debug("save history success!");
    }

    @Override
    public void updateHistory(HistoryDto historyDto) {
        logger.debug("updateHistory parameter is: " + historyDto);
        if (historyDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<History> historyList = historyDao.findByProductionIdAndStationId(historyDto.getProductionId(), historyDto.getStationId());
        if (historyList != null && !historyList.isEmpty()) {
            BeanUtils.copyProperties(historyDto, historyList.get(0));
            logger.debug("update history: " + historyList.get(0));
            historyDao.update(historyList.get(0));
            logger.debug("update history success!");
        }
        else {
            logger.error("can not find this history whose production id is : " + historyDto.getProductionId());
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
    }

    @Override
    public List<HistoryDto> findHistoryListByProductionId(String productionId) {
        logger.debug("findHistoryListByProductionId parameter is: " + productionId);
        List<HistoryDto> historyDtoList = Lists.newArrayList();
        if (StringUtils.isBlank(productionId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<Production> productionList = findProductionById(productionId);
        logger.debug("search production list size: " + productionList.size());
        List<History> historyList = Lists.newArrayList();
        for (Production production : productionList) {
            String id = production.getProductionId();
            List<History> list = historyDao.findByProductionId(id);
            historyList.addAll(list);
        }
        logger.debug("search history list size: " + historyList.size());
        for (History history : historyList) {
            HistoryDto historyDto = new HistoryDto();
            BeanUtils.copyProperties(history, historyDto);
            historyDtoList.add(historyDto);
        }
        return historyDtoList;
    }

    @Override
    public List<HistoryDto> findHistoryListBySerialValue(String serialValue) {
        logger.debug("findHistoryListBySerialValue parameter is: " + serialValue);
        List<HistoryDto> historyDtoList = Lists.newArrayList();
        List<History> historyList = Lists.newArrayList();
        if (StringUtils.isBlank(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        logger.debug("search productionId result: " + productionId);
        if (StringUtils.isNotBlank(productionId)) {
            List<Production> productionList = findProductionById(productionId);
            for (Production production : productionList) {
                String id = production.getProductionId();
                List<History> list = historyDao.findByProductionId(id);
                historyList.addAll(list);
            }
            logger.debug("search total history list size: " + historyList.size());
        }
        for (History history : historyList) {
            HistoryDto historyDto = new HistoryDto();
            BeanUtils.copyProperties(history, historyDto);
            historyDtoList.add(historyDto);
        }
        return historyDtoList;
    }

    @Override
    public ResultDto searchData(String serialValue) {
        logger.debug("searchData parameter is: " + serialValue);
        ResultDto resultDto = new ResultDto();
        List<SerialNumberDto> serialNumberDtoList = Lists.newArrayList();
        List<AttributeDto> attributeDtoList = Lists.newArrayList();
        List<HistoryDto> historyDtoList = Lists.newArrayList();
        List<SerialNumber> serialNumberList = Lists.newArrayList();
        List<Attribute> attributeList = Lists.newArrayList();
        List<History> historyList = Lists.newArrayList();
        Track track = null;
        TrackDto trackDto = null;

        if (StringUtils.isBlank(serialValue)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String productionId = serialNumberDao.findProductionIdBySerialValue(serialValue);
        logger.debug("search productionId result: " + productionId);
        String fgPn = null;
        boolean isHasFgKey = false;
        if (StringUtils.isNotBlank(productionId)) {
            List<Production> productionList = findProductionById(productionId);
            for (Production production : productionList) {
                String id = production.getProductionId();
                List<SerialNumber> serialNumbers = serialNumberDao.findByProductionId(id);
                List<History> histories = historyDao.findByProductionId(id);
                List<Attribute> attributes = attributeDao.findByProductionId(id);
                historyList.addAll(histories);
                serialNumberList.addAll(serialNumbers);
                attributeList.addAll(attributes);
                if (!StringUtils.isBlank(production.getFgPn()) && StringUtils.isBlank(resultDto.getCustomerName())){
                    List<FinishGood> finishGoods =  finishGoodDao.findFgPnByPn(production.getFgPn());
                    if (finishGoods != null && !finishGoods.isEmpty()) {
                        resultDto.setCustomerName(finishGoods.get(0).getCustomerName());
                        fgPn = finishGoods.get(0).getPn();
                    }
                }
            }
            logger.debug("search total history list size: " + historyList.size());
            logger.debug("search total attribute list size: " + attributeList.size());
            logger.debug("search total serialNumber list size: " + serialNumberList.size());
            for (SerialNumber serialNumber : serialNumberList) {
                SerialNumberDto serialNumberDto = new SerialNumberDto();
                BeanUtils.copyProperties(serialNumber, serialNumberDto);
                if (serialNumber.getSerialName().equals(AppConst.FG_END)) {
                    isHasFgKey = true;
                }
                serialNumberDtoList.add(serialNumberDto);
            }
            for (History history : historyList) {
                HistoryDto historyDto = new HistoryDto();
                BeanUtils.copyProperties(history, historyDto);
                historyDtoList.add(historyDto);
            }
            for (Attribute attribute : attributeList) {
                AttributeDto attributeDto = new AttributeDto();
                BeanUtils.copyProperties(attribute, attributeDto);
                attributeDtoList.add(attributeDto);
            }

            productionId = this.getProductionIdOrParentIdBySnId(productionId);
            track = trackDao.findByProductionId(productionId);
            if (track != null) {
                trackDto = new TrackDto();
                logger.debug("search track result: " + track);
                BeanUtils.copyProperties(track, trackDto);
            }
        }
        if (!StringUtils.isBlank(fgPn) && !isHasFgKey) {
            SerialNumberDto serialNumberDto = new SerialNumberDto();
            serialNumberDto.setSerialName(AppConst.FG_END);
            serialNumberDto.setPnValue(fgPn);
            serialNumberDtoList.add(serialNumberDto);
        }
        resultDto.setSerialNumberDtoList(serialNumberDtoList);
        resultDto.setTrackDto(trackDto);
        resultDto.setAttributeList(attributeDtoList);
        resultDto.setHistoryDtoList(historyDtoList);
        return resultDto;
    }

    @Override
    public void updateCurrentStatusToOK(String productionId, String Status) {
        if (StringUtils.isBlank(productionId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Track track = trackDao.findByProductionId(productionId);
        if(track == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
//        String OK = "OK";
        track.setStatus(Status);

//        if (AppConst.RESULT_OK.equals(Status)){
            if(track.getPcba() != null){
                track.setPcba(AppConst.RESULT_OK);
            }
            if(track.getHs() != null){
                track.setHs(AppConst.RESULT_OK);
            }
            if(track.getHou() != null){
                track.setHou(AppConst.RESULT_OK);
            }
//        }

        trackDao.update(track);

        History history = new History();
        history.setProductionId(track.getProductionId());
        history.setStationId(track.getStationId());
        history.setStationName("Manually modification");
        history.setResult(Status);
        history.setCreateTime(new Date());
        if(track.getPcba() != null){
            history.setPcba(AppConst.RESULT_OK);
        }
        if(track.getHs() != null){
            history.setHs(AppConst.RESULT_OK);
        }
        if(track.getHou() != null){
            history.setHou(AppConst.RESULT_OK);
        }
        historyDao.save(history);
    }


    //BOM
    @Override
    public void updateProductionFgPn(String productionId, String fgPn) {
        logger.debug("updateProduction parameter is: " + productionId + ", " + fgPn);
        if (productionId == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Production production = productionDao.findByProductionId(productionId);
        if (production != null) {
            production.setFgPn(fgPn);
        }
        logger.debug("update production: " + production.toString());
        productionDao.update(production);
        logger.debug("update productionFgPn success!");
    }

    @Override
    public boolean validateCustomer(String name) {

        logger.debug("validateCustomer parameter is: " + name);
        if (name == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Customer customer = customerDao.findByName(name);
        if (customer != null) {
            return false;
        }
        return true;
    }

    @Override
    public void createCustomer(CustomerDto customerDto) {
        logger.debug("createProduction parameter is: " + customerDto.toString());
        if (customerDto == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Customer customer = new Customer();
        BeanUtils.copyProperties(customerDto, customer);
        logger.debug("create customer: " + customer.toString());
        customerDao.save(customer);
        logger.debug("save customer success!");
    }

    @Override
    public void createFinishGood(String customerName, String fgPn) {
        logger.debug("createProduction parameter is: " + customerName + "," + fgPn);
        if (customerName == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        FinishGood finishGood = new FinishGood();
        finishGood.setCustomerName(customerName);
        finishGood.setPn(fgPn);
        finishGood.setFgPn(fgPn);
        finishGood.setStatus("Disable");
        finishGood.setKey(AppConst.FINISH_GOOD_KEY_FG);
        logger.debug("create FinishGood: " + finishGood.toString());
        finishGoodDao.save(finishGood);
        logger.debug("save finishGood success!");

        FinishGood finishGoods[] = new FinishGood[9];
        for(int i=0;i<9;i++){
            finishGoods[i] = new FinishGood();
        }
        finishGoods[0].setKey(AppConst.FINISH_GOOD_KEY_HOU);
        finishGoods[1].setKey(AppConst.FINISH_GOOD_KEY_HS);
        finishGoods[2].setKey(AppConst.FINISH_GOOD_KEY_MB_ASSY);
        finishGoods[3].setKey(AppConst.FINISH_GOOD_KEY_PCBA);
        finishGoods[4].setKey(AppConst.FINISH_GOOD_KEY_GW);
        finishGoods[5].setKey(AppConst.FINISH_GOOD_KEY_DSP_P);
        finishGoods[6].setKey(AppConst.FINISH_GOOD_KEY_DSP_S);
        finishGoods[7].setKey(AppConst.FINISH_GOOD_KEY_FCT);
        finishGoods[8].setKey(AppConst.FINISH_GOOD_KEY_EOL);

        for(int i=0;i<9;i++){
            finishGoods[i].setPn("");
            finishGoods[i].setFgPn(fgPn);
            finishGoods[i].setCustomerName(customerName);
            finishGoods[i].setStatus("");
            finishGoodDao.save(finishGoods[i]);
        }
    }

    @Override
    public void updateFinishGood(Map<String,String> pnMap, String customer, String fgPn) {
        logger.debug("updateFinishGood parameter is: " + pnMap + "," + customer + "," + fgPn);
        if (fgPn == null || pnMap.isEmpty() || fgPn==null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<FinishGood> finishGoodList = finishGoodDao.findByCustomerAndFgPn(customer,fgPn);
        String key="";
        String pn="";
        for(FinishGood finishGood:finishGoodList){
            key = finishGood.getKey();
            pn = pnMap.get(key);
            finishGood.setPn(pn);
            finishGoodDao.update(finishGood);
        }
    }

    @Override
    public void updateFinishGoodStatus(String status,String customer,String fgPn) {
        logger.debug("updateFinishGood parameter is: " + status + "," + customer + "," + fgPn);
        if (fgPn == null||status==null||fgPn==null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<FinishGood> finishGoods = finishGoodDao.findFgPnByPn(fgPn);
        if(finishGoods != null && !finishGoods.isEmpty() && finishGoods.size() > 1){
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_ALREADY_EXISTS);
        }
        if (finishGoods != null) {
            finishGoods.get(0).setStatus(status);
            finishGoodDao.update(finishGoods.get(0));
        }
    }

    @Override
    public List<CustomerDto> findCustomers() {
        List<CustomerDto> customerDtoList = Lists.newArrayList();
        List<Customer>  customersList = customerDao.findCustomers();
        logger.debug("find customer: " + customersList.toString());
        if(customersList.isEmpty()){
            return null;
        }
        for(Customer customer:customersList){
            CustomerDto customerDto = new CustomerDto();
            BeanUtils.copyProperties(customer,customerDto);
            customerDtoList.add(customerDto);
        }
        return customerDtoList;
    }

    @Override
    public List<String> findFgPnsByCustomer(String customerName) {
        logger.debug("findFgPnsByCustomer parameter is: " + customerName);
        if (customerName == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<String> resultList = Lists.newArrayList();
        List<FinishGood> finishGoodList = finishGoodDao.findByCustomer(customerName);
        if(finishGoodList.isEmpty()){
            return null;
        }
        String Pn="1";
        for(FinishGood finishGood:finishGoodList){
            if(AppConst.FINISH_GOOD_KEY_FG.equals(finishGood.getKey())) {
                Pn= finishGood.getPn();
                resultList.add(Pn);
            }
        }
        return resultList;

    }

    @Override
    public List<FinishGoodDto> findFinishGoodsByCustomerAndFgPn(String customerName, String fgPn) {
        logger.debug("findFinishGoodsByCustomerAndFgPn parameter is: " + customerName + "," + fgPn);
        if (customerName == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

//        List<FinishGood> finishGood1 = finishGoodDao.findFgPnByPn(fgPn);
//        if(finishGood1 != null && !finishGood1.isEmpty() && finishGood1.size() > 1){
//            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_ALREADY_EXISTS);
//        }
//
//        FinishGoodDto finishGoodDto1 = new FinishGoodDto();
//        BeanUtils.copyProperties(finishGood1.get(0),finishGoodDto1);
//        finishGoodDtoList.add(finishGoodDto1);
        List<FinishGoodDto> finishGoodDtoList = Lists.newArrayList();
        List<FinishGood> finishGoodList = finishGoodDao.findByCustomerAndFgPn(customerName,fgPn);
        logger.debug(finishGoodList.toString());
        if(finishGoodList == null || finishGoodList.isEmpty()){
            return null;
        }
        for(FinishGood finishGood:finishGoodList){
            FinishGoodDto finishGoodDto = new FinishGoodDto();
            BeanUtils.copyProperties(finishGood,finishGoodDto);
            finishGoodDtoList.add(finishGoodDto);
        }
        return finishGoodDtoList;
    }

    @Override
    public String findPnByParentPrIdAndKey(String parentPrId, String key, String status) {
        logger.debug("findPnByParentPrIdAndKey parameter is: " + parentPrId + "," + key);
        if (StringUtils.isBlank(parentPrId) || StringUtils.isBlank(key)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Production production = productionDao.findByProductionId(parentPrId);
        if (production != null) {
            FinishGood finishGood = finishGoodDao.finByFgPnAndKey(production.getFgPn(), key);
            FinishGood finishGood1 = finishGoodDao.finByFgPnAndKey(production.getFgPn(), AppConst.FINISH_GOOD_KEY_FG);
            if (finishGood1 == null ) {
                return null;
            }
            String status1 = finishGood1.getStatus();
            if (finishGood != null && status.equals(status1)) {
                return finishGood.getPn();
            }
        }
        return null;
    }

    @Override
    public boolean validateFgPn(String fgPn) {
        logger.debug("validateFgPn parameter is " + fgPn);
        if(fgPn == null){
            throw new ApplicationException((ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID));
        }
        List<CustomerDto> customerDtoList = findCustomers();
        if(customerDtoList==null){
            return false;
        }
        List<FinishGood> finishGoodList = Lists.newArrayList();
        for(CustomerDto customerDto:customerDtoList){
            Customer customer = new Customer();
            BeanUtils.copyProperties(customerDto,customer);

            //find finishGood by customerName;
            finishGoodList = finishGoodDao.findByCustomer(customer.getName());
            for(FinishGood finishGood:finishGoodList){
                if(finishGood.getFgPn().equals(fgPn) || finishGood.getPn().equals(fgPn)){
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean validatePn(List<String> pns){
        logger.debug("validatePn parameter is " + pns);
        if(pns == null || pns.isEmpty()){
            throw new ApplicationException((ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID));
        }
        List<FinishGood> finishGood = finishGoodDao.finFgPnByPns(pns);
        if (finishGood != null && !finishGood.isEmpty()) {
            return false;
        }
        return true;
    }

    @Override
    public boolean validateFgPnByGwAndPcba(String fgPn, String gwPn, String pcbaPn){
        logger.debug("validateGwAndPcba parameter is : "+ gwPn + "," + pcbaPn);
        if(StringUtils.isBlank(fgPn) || StringUtils.isBlank(gwPn) || StringUtils.isBlank(pcbaPn)){
            throw new ApplicationException((ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID));
        }

        List<FinishGood> pcbaFinishGoods = finishGoodDao.findByPnAndKey(pcbaPn, AppConst.FINISH_GOOD_KEY_PCBA);
        List<FinishGood> gwFinishGoogs = finishGoodDao.findByPnAndKey(gwPn, AppConst.FINISH_GOOD_KEY_GW);

        String preFgPn = "";
        int count = 0;
        for(FinishGood pcbaFinishgood :pcbaFinishGoods){
            for(FinishGood gwFinishGood : gwFinishGoogs){
                if(pcbaFinishgood.getFgPn().equals(gwFinishGood.getFgPn())){
                    count++;
                    preFgPn = gwFinishGood.getFgPn();
                }
            }
        }
        if(count == 0 || (count == 1 && preFgPn.equals(fgPn))){
            return true;
        }
        return false;
    }

    @Override
    public String findFgPnByProductionId(String productionId){
        logger.debug("findFgPnByProductionId parameter is " + productionId);
        if(productionId == null){
            throw new ApplicationException((ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID));
        }
        List<SerialNumber> serialNumbers = serialNumberDao.findByProductionId(productionId);
        String pcbaPn = null;
        String gwPn = null;
        if (serialNumbers != null && !serialNumbers.isEmpty()) {
            for (SerialNumber serialNumber : serialNumbers) {
                if (AppConst.FINISH_GOOD_KEY_PCBA.equals(serialNumber.getSerialName())) {
                    pcbaPn = serialNumber.getPnValue();
                } else if (AppConst.FINISH_GOOD_KEY_GW.equals(serialNumber.getSerialName())) {
                    gwPn = serialNumber.getPnValue();
                }
                if (!StringUtils.isBlank(pcbaPn) && !StringUtils.isBlank(gwPn)) {
                    break;
                }
            }
        }
        List<FinishGood> pcbaFinishGoods = finishGoodDao.findByPnAndKey(pcbaPn, AppConst.FINISH_GOOD_KEY_PCBA);
        List<FinishGood> gwFinishGoogs = finishGoodDao.findByPnAndKey(gwPn, AppConst.FINISH_GOOD_KEY_GW);

        String preFgPn = "";
        int count = 0;
        for(FinishGood pcbaFinishgood :pcbaFinishGoods){
            for(FinishGood gwFinishGood : gwFinishGoogs){
                if(pcbaFinishgood.getFgPn().equals(gwFinishGood.getFgPn())){
                    count++;
                    preFgPn = gwFinishGood.getFgPn();
                    if (gwFinishGood.getStatus().equals(AppConst.STATUS_DISABLE)) {
                        preFgPn = "";
                    }
                }
            }
        }
        if( count == 1){
            return preFgPn;
        }
        return null;
    }

    @Override
    public String findFgPnByParentPrId(String parentId, String status) {
        logger.debug("findFgPnByParentPrId parameter is: " + parentId);
        if (StringUtils.isBlank(parentId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        ProductionDto productionDto = findProductionByProductionId(parentId);
       if (productionDto == null) {
           return null;
       }
        String fgPn = productionDto.getFgPn();
        List<FinishGood> finishGoodList = finishGoodDao.findFgPnByPn(fgPn);
        if(finishGoodList == null || finishGoodList.isEmpty()){
            return  null;
        }
        String status1 = finishGoodList.get(0).getStatus();
        if(!StringUtils.isBlank(fgPn) && status.equals(status1)){
            return fgPn;
        }

        return  null;
    }

    @Override
    public boolean validateParentPrIdIsExist(String parentProductionId) {
        List<Production> productions = productionDao.findByProductionIdOrParentId(parentProductionId);
        if (productions != null && !productions.isEmpty() && productions.size() > 1) {
            return true;
        }
        return false;
    }

    @Override
    public void updateProductionId(SerialNumberDto serialNumberDto) {
        logger.debug("updateSerialNumber parameter is: " + serialNumberDto);
        if (serialNumberDto == null || StringUtils.isBlank(serialNumberDto.getProductionId())
                || StringUtils.isBlank(serialNumberDto.getStationId())
                || StringUtils.isBlank(serialNumberDto.getSerialName())) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        SerialNumber serialNumber = serialNumberDao.findByPSS(serialNumberDto.getProductionId(), serialNumberDto.getStationId(), AppConst.SN_HS);
        if (serialNumber != null) {
            List<SerialNumber> serialNumberList = serialNumberDao.findBySerialValue(serialNumberDto.getSerialValue());
            if (serialNumberList != null && !serialNumberList.isEmpty() && !serialNumberList.get(0).getProductionId().equals(serialNumberDto.getProductionId())){
                serialNumberDao.delete(serialNumberList.get(0).getId());
            }

            Long id = serialNumber.getId();
            BeanUtils.copyProperties(serialNumberDto, serialNumber);
            logger.debug("update serialNumber: " + serialNumber);
            serialNumber.setId(id);
            serialNumberDao.update(serialNumber);
            logger.debug("update serialNumber success!");
        } else {
            serialNumber = serialNumberDao.findBySerialValueAndName(serialNumberDto.getSerialValue(),serialNumberDto.getSerialName());
            if (serialNumber != null) {
                Long id = serialNumber.getId();
                BeanUtils.copyProperties(serialNumberDto, serialNumber);
                logger.debug("update serialNumber: " + serialNumber);
                serialNumber.setId(id);
                serialNumberDao.update(serialNumber);
                logger.debug("update serialNumber success!");
            } else {
                logger.error("can not find this serialNumber whose production id is : " + serialNumberDto.getProductionId());
                throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
            }
        }
    }

    @Override
    public List<Production> findchildrenbyId(String productionId) {
        List<Production> production = productionDao.findchildrenbyId(productionId);
        return productionDao.findchildrenbyId(productionId);
    }

    private List<Production> findProductionById(String id) {
        logger.debug("parameter: " + id);
        Production _production = productionDao.findByProductionId(id);
        if (_production == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
        logger.debug("search production result: " + _production);
        String parentId = _production.getParentId();
        String pid = _production.getProductionId();
        if (StringUtils.isNotBlank(parentId)) {
            pid = _production.getParentId();
        }
        List<Production> productionList = productionDao.findByProductionIdOrParentId(pid);
        logger.debug("search production list size: " + productionList.size());
        return productionList;
    }

    private String getProductionIdOrParentIdBySnId (String productionId) {
        if (productionId == null) {
            return null;
        }
        Production production = productionDao.findByProductionId(productionId);
        if (production == null) {
            return null;
        }
        if (StringUtils.isNotBlank(production.getParentId())) {
            productionId = production.getParentId();
        } else {
            productionId = production.getProductionId();
        }
        return productionId;
    }

    //FinishGoodDto finFinishGoodByPcbaPnAndGwPn (String pcbaPn, String gwPn);

    //FinishGoodDto finFinishGoodByFgPnAndKey (String fgPn, String key);
}
